/**
* Copyright (c) 2004-2013 Luciano Xumerle. All rights reserved.
*
* This file is part of gephinfo.
*
* gephinfo is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
**/

package it.ciano.util;

import java.util.*;

/**
 * A class to manage parameter readed from a command line
 *
 * @author Luciano Xumerle
 * @version 0.0.3
 */
public class ReadPar
{
    // FULL PARAMETER MAP
    private HashMap pars;
    private ArrayList _order;
    // optional additional parameters
    private ArrayList addpar;
    // NUMBER OF OPTIONALS PARS ALLOWED
    private int numberOfParameters;
    // DEFAULT SINTAX HELP
    private String sintaxHelp;
    // IS ALL OK
    private boolean paramOK;
    // PROGRAM NAME
    private String programName;
    // AUTHOR NAME
    private String author;
    // PROGRAM VERSION
    private String programVersion;
    // RELEASE DATE
    private String releaseDate;
    // COPYRIGHT
    private String copyRight;
    // first year on copyright info
    private String _sYear;

    /**
     * Class constructor.
     *
     * @param numOfPar Number of optional parameter.
     * @param startYearOnCopyrigth first year of copyrigth.
     */
    public ReadPar ( int numOfPar, String startYearOnCopyrigth )
    {
        numberOfParameters = numOfPar;
        pars = new HashMap();
        _order = new ArrayList();
        addpar = new ArrayList();
        sintaxHelp = "";
        _sYear = startYearOnCopyrigth;
        paramOK = true;
    }

    /**
     * Class constructor.
     *
     * @param numOfPar Number of optional parameter.
     */
    public ReadPar ( int numOfPar )
    {
        this ( numOfPar, "2000" );
    }

    /**
     * The method add a new parameter to the list
     *
     * @param parname the parameter's name
     * @param help    the parameter's help
     * @param withValue the parameter has (true) a value
     */
    public void addPar ( String parname, String help, boolean withValue )
    {
        pars.put ( parname, new Parameter ( parname, "", help, withValue ) );
        _order.add ( parname );
    }

    /**
     * The parameter given in input has a white line after the help line
     *
     * @param parameter paramer's name
     */
    public void addWhiteHelpLine ( String parameter )
    {
        if ( pars.containsKey ( parameter ) )
            ( ( Parameter ) pars.get ( parameter ) ).setWhiteLine();
    }

    /**
     * Set the help string
     *
     * @param str
     */
    public void addSintaxHelp ( String str )
    {
        sintaxHelp = str + "\n";
    }

    /**
     * The method set the program's informations.
     *
     * @param name    program name
     * @param version program version
     * @param date    release date
     * @param cp      copyright info
     */
    public void addMessageInfo ( String name, String version, String date, String cp, String auth )
    {
        programName = name;
        programVersion = version;
        releaseDate = date;
        copyRight = cp;
        author = auth;
    }

    /**
      * The method checks if parameters are ok
      *
      * @return true or false
      */
    public boolean checkPar()
    {
        return paramOK;
    }

    /**
     * The method parse a command line parameter list.
     *
     * @param input a parameter String array
     *
     */
    public void parsePar ( String[] input )
    {
        boolean ret = true;
        String nextpar = "0";
        for ( int i = 0; i < input.length; i++ )
        {
            if ( nextpar.equals ( "0" ) )
            {
                boolean ispar = false;
                String cpar = trimParameter ( input[ i ] );
                if ( !cpar.equals ( "" ) && pars.containsKey ( cpar ) )
                {
                    ispar = true;
                    ( ( Parameter ) pars.get ( cpar ) ).setSelected();
                    if ( parWithValue ( cpar ) )
                    {
                        nextpar = "1";
                        if ( ( i + 1 ) < input.length )
                            ( ( Parameter ) pars.get ( cpar ) ).setValue ( input[ i + 1 ] );
                        else
                            ret = false;
                    }
                }

                if ( !ispar )
                {
                    if ( addpar.size() < numberOfParameters )
                        addpar.add ( input[ i ] );
                    else
                        ret = false;
                }
            }
            else
                nextpar = "0";
        }
        // SET TO EMPTY STRING UNDEFINED PAR
        for ( int i = addpar.size(); i < numberOfParameters; i++ )
            addpar.add ( "" );
        // SET paramOk
        paramOK = ret ;
    }

    /**
     * The method gets the optional additional paramter at index i.
     *
     * @param i parameter index.
     * @return String with the parameter name. Returns null if wrong i.
     */
    public String getOptionalAdditionalPar ( int i )
    {
        if ( i > 0 && i <= addpar.size() )
            return ( String ) addpar.get ( i -1 );
        return "";
    }

    /**
     * Returns each additional parameter or null if there is no parameter.
     *
     * @return each additional parameter or null if there is no parameter.
     */
    public String[] getOptionalAdditionalPars()
    {
        if ( addpar.size() >0 )
            return ( String[] ) addpar.toArray ( new String[addpar.size() ] );
        return null;
    }

    /**
     * The method checks if paramter is set
     *
     * @param par paramter name
     * @return true or false
     */
    public boolean isParameterSet ( String par )
    {
        return ( ( Parameter ) pars.get ( par ) ).isSelected();
    }

    /**
     * The method checks if paramter has a value
     *
     * @param par paramter name
     * @return true or false
     */
    public boolean parWithValue ( String par )
    {
        return ( ( Parameter ) pars.get ( par ) ).withValue();
    }

    /**
     * Checks if the parameter is set.
     * Returns -1 when false and index when true.
     *
     * @param par parameter name.
     * @return the index of parameter if it is selected.
     */
    public int getParIndex ( String par )
    {
        for ( int i = 0; i < _order.size(); i++ )
        {
            if ( _order.get ( i ).equals ( par )
                    && ( ( Parameter ) pars.get ( par ) ).isSelected() )
                return i;
        }
        return -1;
    }

    /**
     * The method gets the parameter value by index
     *
     * @param index parameter index
     * @return parameter value
     */
    public String getParFromIndex ( int index )
    {
        return getParValue ( ( String ) _order.get ( index ) ) ;
    }

    /**
     * The method gets parameter value by parameter name
     *
     * @param par parameter name
     * @return parameter value
     */
    public String getParValue ( String par )
    {
        return ( ( Parameter ) pars.get ( par ) ).getValue();
    }

    /**
     * Overriding toString
     *
     * @return String with the selected parameters
     */
    public String toString()
    {
        String pp = "PARAMETERS:\n";
        for ( int i = 0; i < addpar.size(); i++ )
            pp += "- parameter " + ( i + 1 ) + " is : " + addpar.get ( i ) + "\n";
        pp += "Options:\n";
        for ( int i = 0; i < _order.size(); i++ )
        {
            String cpar = ( String ) _order.get ( i );
            if ( ( ( Parameter ) pars.get ( cpar ) ).isSelected() )
                pp += "- option '" + cpar +
                        "' with value '" + getParValue ( cpar ) + "'\n";
        }
        return pp + "\n";
    }

    /**
     * The method prints program &amp; copyright info
     */
    public void doMsg ( )
    {
        String yy = _sYear;
        if ( !_sYear.equals ( copyRight ) )
            yy += "-" + copyRight;
        String version = programName + " version " +
                programVersion + " (" + releaseDate + ")\n";
        String cr = "Copyright (C) " + yy + " by " + author + "\n";
        String notice1 = "This is free software; see the source for copying conditions. There is NO\n";
        String notice2 = "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n";
        String help = "[-h] : Print help.\n";
        String line = "";
        int ln = Math.max ( Math.max ( version.length(), cr.length() ), notice2.length() );
        for ( int i = 1; i < ln; i++ )
            line += "-";
        System.err.println ( line + "\n" + version + cr + notice1 + notice2 + help + line );
    }

    /**
     * The method prints program help page
     */
    public void doHelp()
    {
        String pp = "SINTAX:\n " + sintaxHelp;
        pp += "\nOPTIONS:\n";
        for ( int i = 0; i < _order.size(); i++ )
        {
            String cpar = ( String ) _order.get ( i );
            String space = "";
            String value = cpar;
            if ( ( ( Parameter ) pars.get ( cpar ) ).withValue() )
                value += " <par>";
            int cc = 11 - value.length();
            for ( int y = 0; y < cc; y++ )
                space += " ";
            pp += space + "-" + value + " : "
                    + ( ( Parameter ) pars.get ( cpar ) ).getHelp() + "\n";
            if ( ( ( Parameter ) pars.get ( cpar ) ).withWhiteLine() )
                pp += "\n";
        }
        System.out.println ( pp );
    }

    /**
     * The method trims initial dashes from a command line parameter.
     * Example 1: "--par" becomes "par".
     * Example 2: "-par" becomes "par".
     *
     * @param par the parameter given from command line
     * @return parameter without dash
     */
    public static String trimParameter ( String par )
    {
        if ( par.startsWith ( "--" ) )
            return par.substring ( 2 );
        else if ( par.startsWith ( "-" ) )
            return par.substring ( 1 );
        return "";
    }

} // end class

